package com.pactera.asmp.server.service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.google.common.collect.Lists;
import com.pactera.asmp.server.common.constants.ScreenRedisKey;
import com.pactera.asmp.server.dao.ConstantInfoMapper;
import com.pactera.asmp.server.dao.ProjectModuleMapper;
import com.pactera.asmp.server.dao.ScriptInfoMapper;
import com.pactera.asmp.server.dao.TaskMapper;
import com.pactera.asmp.server.dao.TestReportErrorVideoInfoMapper;
import com.pactera.asmp.server.dao.TestReportMapper;
import com.pactera.asmp.server.dao.UseCaseInfoMapper;
import com.pactera.asmp.server.entity.ConstantStatisticsDataDTO;
import com.pactera.asmp.server.entity.ProjectModuleDTO;
import com.pactera.asmp.server.entity.ProjectModuleSearch;
import com.pactera.asmp.server.entity.ProjectStatisticsDataDTO;
import com.pactera.asmp.server.entity.ResponseResult;
import com.pactera.asmp.server.entity.ScreenMasterComputerInfoDTO;
import com.pactera.asmp.server.entity.ScreenProjectInfoDTO;
import com.pactera.asmp.server.entity.ScreenTaskInfoDTO;
import com.pactera.asmp.server.entity.ScriptStatisticsDataDTO;
import com.pactera.asmp.server.entity.TaskExceTimeDataDTO;
import com.pactera.asmp.server.entity.TaskReportList;
import com.pactera.asmp.server.entity.TaskReportListVO;
import com.pactera.asmp.server.entity.UserProjectStatisticsDataDTO;
import com.pactera.asmp.server.utils.AssertUtil;
import com.pactera.asmp.server.utils.DateUtil;

@Service
public class CenterLargeScreenServiceImpl implements ICenterLargeScreenService {

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private ConstantInfoMapper constantInfoMapper;

    @Autowired
    private ScriptInfoMapper scriptInfoMapper;

    @Autowired
    private TestReportMapper testReportMapper;

    @Autowired
    private ProjectModuleMapper projectModuleMapper;

    @Autowired
    private UseCaseInfoMapper useCaseInfoMapper;

    @Autowired
    private TestReportErrorVideoInfoMapper testReportErrorVideoInfoMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public ResponseResult getTaskStatisticsData(Integer projectId) {
        AssertUtil.notNull(projectId, "项目ID不允许为空");

        ScreenTaskInfoDTO screenTaskInfoDTO = new ScreenTaskInfoDTO();
 
        // 任务执行次数相关数据
        ProjectStatisticsDataDTO projectStatisticsDataDTO = taskMapper.summaryTaskByProjectId(projectId);
        if(null != projectStatisticsDataDTO) {
            screenTaskInfoDTO.setTaskExeNum(projectStatisticsDataDTO.getExeNum());
            screenTaskInfoDTO.setTaskSuccessNum(projectStatisticsDataDTO.getSuccessNum());
            screenTaskInfoDTO.setTaskFailNum(projectStatisticsDataDTO.getFailNum());
            screenTaskInfoDTO.setScriptNum(projectStatisticsDataDTO.getScriptNum());
            if(projectStatisticsDataDTO.getExeNum() == null || projectStatisticsDataDTO.getExeNum() == 0L) {
                screenTaskInfoDTO.setTaskSuccessRate(BigDecimal.ZERO);
                screenTaskInfoDTO.setTaskFailRate(BigDecimal.ZERO);
            }else {
                screenTaskInfoDTO.setTaskSuccessRate(new BigDecimal(projectStatisticsDataDTO.getSuccessNum()).divide(new BigDecimal(projectStatisticsDataDTO.getExeNum()), 4, BigDecimal.ROUND_HALF_UP));
                screenTaskInfoDTO.setTaskFailRate(new BigDecimal(projectStatisticsDataDTO.getFailNum()).divide(new BigDecimal(projectStatisticsDataDTO.getExeNum()), 4, BigDecimal.ROUND_HALF_UP));
            }
        }
        String lastStr = LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern(DateUtil.DATE_FORMAT_YYYYMM));
        Object promoteRate = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_TASK_LASTMONTH_PROMOTERATE + lastStr, projectId.toString());
        if(null == promoteRate) {
            screenTaskInfoDTO.setTaskLastMonthGrowRate(BigDecimal.ZERO);
        }else {
            screenTaskInfoDTO.setTaskLastMonthGrowRate(new BigDecimal(promoteRate.toString()));
        }
        // 项目关联的常量总数
        ConstantStatisticsDataDTO constantDataDTO = constantInfoMapper.summaryConstantByProjectId(projectId);
        screenTaskInfoDTO.setConstantTotalNum(constantDataDTO.getTotalNum());
        screenTaskInfoDTO.setConstantServiceNum(constantDataDTO.getServiceNum());

        // 常量模块分布
        screenTaskInfoDTO.setConstantModuleStatisticsDataDTOs(constantInfoMapper.summaryModuleConstantByProjectId(projectId));

        // 脚本模块分布
        screenTaskInfoDTO.setScriptModuleStatisticsDataDTOs(scriptInfoMapper.summaryModuleScriptInfoByProjectId(projectId));

        // 各模块脚本执行情况
        List<TaskReportListVO> taskReportListVOs = getProjectReportChartModuleExec(projectId);
        screenTaskInfoDTO.setTaskReportListVOs(taskReportListVOs);
        // 失败率T10脚本模块
        if(CollectionUtils.isNotEmpty(taskReportListVOs)) {
            List<TaskReportListVO> taskReportListVOsTop10 = Lists.newArrayList();
            Collections.sort(taskReportListVOs, new Comparator<TaskReportListVO>() {
                @Override
                public int compare(TaskReportListVO v1, TaskReportListVO v2) {
                    if(v1.getFailRate() == null || v1.getFailRate().compareTo(BigDecimal.ZERO) == 0) {
                        return 1;
                    }
                    if(v2.getFailRate() == null || v2.getFailRate().compareTo(BigDecimal.ZERO) == 0) {
                        return -1;
                    }
                    return v2.getFailRate().compareTo(v1.getFailRate());
                }
            });
            if(taskReportListVOs.size() <= 10) {
                taskReportListVOsTop10.addAll(taskReportListVOs);
            }else {
                taskReportListVOsTop10.addAll(taskReportListVOs.subList(0, 10));
            }
            screenTaskInfoDTO.setTaskReportListVOsTop10(taskReportListVOsTop10);
        }
        return ResponseResult.defaultSuccess(screenTaskInfoDTO);
    }


    private List<TaskReportListVO> getProjectReportChartModuleExec(Integer projectId) {
        AssertUtil.notNull(projectId,"项目Id不允许为空");

        List<TaskReportList> taskReportList = testReportMapper.getProjectReportChartModuleExec(projectId);
        if(CollectionUtils.isEmpty(taskReportList)) return new ArrayList<>();
        Map<Integer, List<TaskReportList>> taskReportMap = taskReportList.stream().collect(Collectors.groupingBy(TaskReportList::getModuleId));

        List<ProjectModuleDTO> projectModules = projectModuleMapper.select(new ProjectModuleSearch() {{setProjectId(projectId);}});
        if(CollectionUtils.isEmpty(projectModules)) {
            return Lists.newArrayList();
        }

        List<TaskReportListVO> taskReportListVOList = new ArrayList<>();
        for(ProjectModuleDTO projectModuleDTO : projectModules) {
            TaskReportListVO taskReportListVO = new TaskReportListVO();
            List<TaskReportList> eachTaskReportList = taskReportMap.get(projectModuleDTO.getId());
            if(CollectionUtils.isEmpty(eachTaskReportList)) {
                taskReportListVO.setModuleId(projectModuleDTO.getId());
                taskReportListVO.setModuleName(projectModuleDTO.getName());
                taskReportListVO.setPass(0);
                taskReportListVO.setFail(0);
                taskReportListVO.setFailRate(BigDecimal.ZERO);
                taskReportListVOList.add(taskReportListVO);
                continue;
            }
            Optional<TaskReportList> pass = eachTaskReportList.stream().filter(x -> x.getStatus().intValue() == 1).findFirst();
            if(pass.isPresent()) {
                taskReportListVO.setPass(pass.get().getCount());
            }else {
                taskReportListVO.setPass(0);
            }
            Optional<TaskReportList> fail = eachTaskReportList.stream().filter(x -> x.getStatus().intValue() == 0).findFirst();
            if(fail.isPresent()) {
                taskReportListVO.setFail(fail.get().getCount());
            }else {
                taskReportListVO.setFail(0);
            }
            taskReportListVO.setModuleId(projectModuleDTO.getId());
            taskReportListVO.setModuleName(projectModuleDTO.getName());
            int total = taskReportListVO.getFail().intValue() + taskReportListVO.getPass().intValue();
            if(total > 0) {
                taskReportListVO.setFailRate(new BigDecimal(taskReportListVO.getFail()).divide(new BigDecimal(total), 4, BigDecimal.ROUND_HALF_UP));
            }
            taskReportListVOList.add(taskReportListVO);
        }
        for(Integer moduleId : taskReportMap.keySet()){}
        return taskReportListVOList;
    }


    @Override
    public ResponseResult getMasterComputerStatisticsData(Integer projectId, Integer masterComputerId) {
        AssertUtil.notNull(projectId, "项目ID不允许为空");
        AssertUtil.notNull(masterComputerId, "上位机ID不允许为空");

        ScreenMasterComputerInfoDTO screenMasterComputerInfoDTO = new ScreenMasterComputerInfoDTO();
        Object obj = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_TASK_EXCETIME_BY_MASTERCOMPUTE + projectId, masterComputerId.toString());
        if(null != obj) {
            List<TaskExceTimeDataDTO> curTaskExceTimeDataDTOs = JSON.parseObject(obj.toString(), new TypeReference<List<TaskExceTimeDataDTO>>() {});
            curTaskExceTimeDataDTOs.stream().sorted((v1, v2) -> {
                if(StringUtils.isEmpty(v1.getExceMonth())) {
                    return -1;
                }
                if(StringUtils.isEmpty(v2.getExceMonth())) {
                    return 1;
                }
                return v1.getExceMonth().compareTo(v2.getExceMonth());
            });
            if(curTaskExceTimeDataDTOs.size() > 12) {
                screenMasterComputerInfoDTO.setTaskExceTimeDataDTOs(curTaskExceTimeDataDTOs.subList(0, 12));
            }else {
                screenMasterComputerInfoDTO.setTaskExceTimeDataDTOs(curTaskExceTimeDataDTOs);
            }
        }
        Object objFreeTime = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_FREETIME_BY_MASTERCOMPUTE, String.valueOf(masterComputerId));
        if(null != objFreeTime) {
            BigDecimal hour = new BigDecimal(objFreeTime.toString()).divide(new BigDecimal(60 * 60), 0, BigDecimal.ROUND_HALF_UP);
            screenMasterComputerInfoDTO.setComputerFreeTime(hour.longValue());
        }
        Object objUsedTime = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_EXCETIME_BY_MASTERCOMPUTE, String.valueOf(masterComputerId));
        if(null != objUsedTime) {
            BigDecimal hour = new BigDecimal(objUsedTime.toString()).divide(new BigDecimal(60 * 60), 0, BigDecimal.ROUND_HALF_UP);
            screenMasterComputerInfoDTO.setComputerUsedTime(hour.longValue());
        }
        Object objNightUsedTime = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_EXCETIME_BYNIGHT_MASTERCOMPUTE, String.valueOf(masterComputerId));
        if(null != objNightUsedTime) {
            BigDecimal hour = new BigDecimal(objNightUsedTime.toString()).divide(new BigDecimal(60 * 60), 0, BigDecimal.ROUND_HALF_UP);
            screenMasterComputerInfoDTO.setComputerNightUsedTime(hour.longValue());
        }
        Object objDailyUsedRate = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_EXCERATE_BY_MASTERCOMPUTE, String.valueOf(masterComputerId));
        if(null != objDailyUsedRate) {
            screenMasterComputerInfoDTO.setComputerDailyUsedRate(new BigDecimal(objDailyUsedRate.toString()));
        }
        Object objLastMonthIncreaseRate = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_MASTERCOMPUTE_LASTMONTH_INCREASE_EXCERATE, String.valueOf(masterComputerId));
        if(null != objLastMonthIncreaseRate) {
            screenMasterComputerInfoDTO.setComputerLastMonthIncreaseRate(new BigDecimal(objLastMonthIncreaseRate.toString()));
        }

        // 台架设备屏幕异常情况
        screenMasterComputerInfoDTO.setTaskErrorVideoDataDTO(testReportErrorVideoInfoMapper.summaryErrorVideoInfoByProjectId(projectId, masterComputerId));
        return ResponseResult.defaultSuccess(screenMasterComputerInfoDTO);
    }


    @Override
    public ResponseResult getProjectStatisticsData(Integer projectId) {
        AssertUtil.notNull(projectId, "项目ID不允许为空");

        ScreenProjectInfoDTO screenProjectInfoDTO = new ScreenProjectInfoDTO();
        Object objCreateHour = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_PROJECT_CREATEHOUR, String.valueOf(projectId));
        if(null != objCreateHour) {
            screenProjectInfoDTO.setProjectCreateHour(Long.parseLong(objCreateHour.toString()));
        }
        screenProjectInfoDTO.setProjectScriptNum(scriptInfoMapper.summaryScriptInfoByProjectId(projectId));
        screenProjectInfoDTO.setProjectUseCaseNum(useCaseInfoMapper.summaryUseCaseByProjectId(projectId));
        screenProjectInfoDTO.setProjectTaskNum(taskMapper.summaryTaskCountByProjectId(projectId));
        screenProjectInfoDTO.setProjectConstantNum(constantInfoMapper.summaryConstantCountByProjectId(projectId));

        Object objSave = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_SAVETIME_BYMONTH_PROJECT, String.valueOf(projectId));
        if(null != objSave) {
            String[] strs= objSave.toString().split(",");
            screenProjectInfoDTO.setProjectSaveHour(Long.parseLong(strs[0]));
            screenProjectInfoDTO.setProjectSaveHumanRes(Long.parseLong(strs[1]));
        }else {
            screenProjectInfoDTO.setProjectSaveHour(0L);
            screenProjectInfoDTO.setProjectSaveHumanRes(0L);
        }
        if(screenProjectInfoDTO.getProjectUseCaseNum() != null && screenProjectInfoDTO.getProjectUseCaseNum() != 0) {
            screenProjectInfoDTO.setProjectUseCaseConvertRate(new BigDecimal(screenProjectInfoDTO.getProjectScriptNum())
                    .divide(new BigDecimal(screenProjectInfoDTO.getProjectUseCaseNum()), 4, BigDecimal.ROUND_HALF_UP));
        }else {
            screenProjectInfoDTO.setProjectUseCaseConvertRate(BigDecimal.ZERO);
        }

        Object objUser = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_PROJECT_USER_SPREAD, projectId.toString());
        if(null != objUser) {
            screenProjectInfoDTO.setUserProjectDataDTOs(JSON.parseObject(objUser.toString(), new TypeReference<List<UserProjectStatisticsDataDTO>>() {}));
        }
        Object objCategory = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_SCRIPT_BY_CATEGORY, projectId.toString());
        if(null != objCategory) {
            screenProjectInfoDTO.setScriptByCategoryList(JSON.parseObject(objCategory.toString(), new TypeReference<List<ScriptStatisticsDataDTO>>() {}));
        }
        Object objScriptUser = redisTemplate.opsForHash().get(ScreenRedisKey.REDIS_KEY_SCREEN_SCRIPT_BY_USER, projectId.toString());
        if(null != objScriptUser) {
            screenProjectInfoDTO.setScriptByUserList(JSON.parseObject(objScriptUser.toString(), new TypeReference<List<ScriptStatisticsDataDTO>>() {}));
        }

        // TODO 对接jira接口
        return ResponseResult.defaultSuccess(screenProjectInfoDTO);
    }
}
